/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 *
 */

import fse from 'fs-extra';
import { maxSatisfying, valid } from 'semver';

import { ProjectBuildProfile } from '../options/build/project-build-profile.js';
import RemoteHspOpt = ProjectBuildProfile.RemoteHspOpt;
import { Module } from '@ohos/hvigor';
import path from 'path';

import { BuildArtifactExtension } from '../const/build-directory-const.js';
import { CommonConst } from '../const/common-const.js';
import { RemoteHspMetadata } from '../tasks/abstract/abstract-generate-metadata.js';

import { OhosLogger } from './log/ohos-logger.js';
import { strMapToObj } from './map-util.js';
import SigningConfigBuildOpt = ProjectBuildProfile.SigningConfigBuildOpt;
import { isSigned } from '../tasks/sign/sign-util.js';

import { ohPackageLoader } from './loader/file/oh-package-loader.js';
import { ModuleTaskService } from '../tasks/service/module-task-service.js';
import { ProjectTaskService } from '../tasks/service/project-task-service.js';
import { Dependency } from '../project/dependency/core/dependency-interface.js';

const _log: OhosLogger = OhosLogger.getLogger('remote-hsp-info');

export interface RemoteHspCacheOpt {
  // 当前remoteHsp包签名使用的签名信息
  signingConfig: SigningConfigBuildOpt;

  // remoteHsp相关信息
  signedRemoteHsps: Map<string, SignedRemoteHspOpt>;
}

export interface SignedRemoteHspOpt {
  // hsp文件名
  hspFileName: string;

  // hsp目录名
  hspDirName: string;

  // hsp版本
  version: string;

  // hsp签名前路径
  hspPath: string;

  // hsp签名后路径
  signedHspPath: string;

  // 是否签名
  isSigned: boolean;

  // 模块名，用于处理签名远程仓上集成态hsp时增量问题
  moduleName?: string;
}

/**
 * 获取当前模块需要打包的remote_hsp
 * 提供给外部使用的方法，为了支持在线签名，非需求变动不要轻易修改
 *
 * @param module hvigor项目中的子模块module
 * @param module
 */
export const getRemoteHspObjList = (module: Module): RemoteHspOpt[] => {
  const project = module.getProject();
  const moduleRemoteHspPath = path.resolve(module.getNodeDir(), CommonConst.OH_MODULES, BuildArtifactExtension.DOT_HSP);
  const projectRemoteHspPath = path.resolve(project.getNodeDir(), CommonConst.OH_MODULES, BuildArtifactExtension.DOT_HSP);
  const moduleRemoteHspMap = getRemoteHspMap(moduleRemoteHspPath);
  const allRemoteHspMap = getRemoteHspMap(projectRemoteHspPath, moduleRemoteHspMap);
  return allRemoteHspMap ? [...allRemoteHspMap.values()] : [];
};

/**
 * 通过remoteHsp的路径获取到remoteHsp信息
 *
 * @param remoteHspPath remoteHsp的路径信息
 * @param allRemoteHspMap 已经保存的remoteHsp信息，用于确保同名remoteHsp包只存在一个最高版本的
 */
export const getRemoteHspMap = (remoteHspPath: string, allRemoteHspMap?: Map<string, RemoteHspOpt>): Map<string, RemoteHspOpt> | undefined => {
  if (!fse.existsSync(remoteHspPath)) {
    _log.debug('allRemoteHspMap does not exist.');
    return allRemoteHspMap;
  }
  if (allRemoteHspMap) {
    _log.debug(`allRemoteHspMap: ${JSON.stringify(strMapToObj(allRemoteHspMap))}`);
  }
  const allRequiredSignRemoteHspMap: Map<string, RemoteHspOpt> = allRemoteHspMap ?? new Map<string, RemoteHspOpt>();
  const hspModules = fse.readdirSync(remoteHspPath);
  for (const hspDirItem of hspModules) {
    const hspDirPath = path.resolve(remoteHspPath, hspDirItem);
    const currentRemoteHspObj: RemoteHspOpt | undefined = getRemoteHspObj(hspDirPath, hspDirItem, _log);
    if (currentRemoteHspObj && checkIfNeedSet(currentRemoteHspObj, _log, allRemoteHspMap)) {
      allRequiredSignRemoteHspMap.set(currentRemoteHspObj.hspFileName, { ...currentRemoteHspObj });
    }
  }
  return allRequiredSignRemoteHspMap;
};

/**
 * 判断是否需要将remoteHsp信息存入到map中
 *
 * @param currentRemoteHspObj
 * @param log
 * @param allRemoteHspMap
 */

const checkIfNeedSet = (currentRemoteHspObj: RemoteHspOpt, log: OhosLogger, allRemoteHspMap?: Map<string, RemoteHspOpt>): boolean => {
  // 如果不存在allRemoteHspMap，则不需要判断包版本，返回true
  if (!allRemoteHspMap) {
    log.debug(
      `allRemoteHspMap does not exist, ${currentRemoteHspObj.hspFileName} ${currentRemoteHspObj.hspVersion} ` +
        'should be stored in the allRequiredSignRemoteHspMap',
    );
    return true;
  }
  const ifHasCurrentRemoteHsp = allRemoteHspMap.get(currentRemoteHspObj.hspFileName);

  // 如果存在allRemoteHspMap但当前RemoteHsp不在map中则返回true
  if (!ifHasCurrentRemoteHsp) {
    log.debug(
      `allRemoteHspMap exists, but ${currentRemoteHspObj.hspFileName} is not in allRemoteHspMap, ` +
        `${currentRemoteHspObj.hspFileName} ${currentRemoteHspObj.hspVersion} ` +
        'should be stored in the allRequiredSignRemoteHspMap',
    );
    return true;
  }

  // 如果存在allRemoteHspMap并且当前RemoteHsp存在map中则进一步判断版本号大小，如果当前RemoteHsp版本号优先级高则返回true
  if (compareIfSetRemoteHsp(currentRemoteHspObj, allRemoteHspMap)) {
    log.debug(
      `allRemoteHspMap exists, ${currentRemoteHspObj.hspFileName} is in allRemoteHspMap, ` +
        `but ${currentRemoteHspObj.hspFileName} ${currentRemoteHspObj.hspVersion} is higher, ` +
        `${currentRemoteHspObj.hspFileName} ${currentRemoteHspObj.hspVersion} ` +
        'should be stored in the allRequiredSignRemoteHspMap',
    );
    return true;
  }
  log.debug(`${currentRemoteHspObj.hspFileName} ${currentRemoteHspObj.hspVersion} ` + 'should not be stored in the allRequiredSignRemoteHspMap');
  return false;
};

/**
 * 获取远程hsp的hspName/hspVersion/hspPath
 *
 * @param hspDirPath
 * @param hspDirName
 * @param log
 */
export const getRemoteHspObj = (hspDirPath: string, hspDirName: string, log: OhosLogger): RemoteHspOpt | undefined => {
  if (!fse.existsSync(hspDirPath)) {
    return undefined;
  }
  const hspPackage = fse.readdirSync(hspDirPath);
  let currentRemoteHspFileName: string | undefined;
  let currentRemoteHspData: RemoteHspOpt | undefined;
  for (const hspItem of hspPackage) {
    if (hspItem.endsWith(BuildArtifactExtension.DOT_HSP)) {
      if (currentRemoteHspFileName) {
        log.printErrorExit('ALLOW_ONE_HSP', [hspDirPath], [[hspDirPath]]);
      }
      currentRemoteHspFileName = hspItem;
    }
    if (hspItem.includes(CommonConst.OH_PACKAGE_JSON5)) {
      const ohPackagePath = ohPackageLoader.getNodeOhPackagePath(path.resolve(hspDirPath, CommonConst.OH_PACKAGE_JSON5));
      currentRemoteHspData = getHspBaseData(ohPackagePath, log);
    }
  }

  if (!currentRemoteHspData) {
    log.printErrorExit('NO_PACKAGE_FOUND', [currentRemoteHspFileName, hspDirPath], [[hspDirPath]]);
    return undefined;
  } else if (!currentRemoteHspFileName) {
    log.printErrorExit('NO_HSP_FOUND', [hspDirPath], [[hspDirPath]]);
    return undefined;
  } else {
    currentRemoteHspData.hspFileName = currentRemoteHspFileName;
    currentRemoteHspData.hspPath = path.resolve(hspDirPath, currentRemoteHspFileName);
    currentRemoteHspData.hspDirName = hspDirName;
    return currentRemoteHspData;
  }
};

/**
 * 通过远程hsp路径下的oh-package.json获取hspName和hspVersion
 *
 * @param ohPackagePath
 * @param log
 */
export const getHspBaseData = (ohPackagePath: string, log: OhosLogger): RemoteHspOpt | undefined => {
  if (!fse.existsSync(ohPackagePath)) {
    return undefined;
  }
  const jsonData = fse.readJsonSync(ohPackagePath);
  if (!valid(jsonData?.version)) {
    log.printErrorExit('VERSION_ILLEGAL', [ohPackagePath]);
  }
  return {
    hspName: jsonData.name,
    hspVersion: jsonData.version,
    hspPath: '',
    hspDirName: '',
    hspFileName: '',
    isIntegratedHsp: !!jsonData?.metadata?.integratedHsp,
  };
};

/**
 * 判断是否需要将当前远程hsp打包
 * ver1大于ver2返回1 小于返回-1 相等返回0 现版本比较方法为 正式版本1.0.1 > 正式版本1.0.0 正式版本1.0.1 > 先行版本1.0.1-rsc
 * 正式版本1.0.1 > 先行版本1.0.2-rsc 先行版本1.0.1-rsc > 先行版本1.0.1-rs 先行版本1.0.2-rs > 先行版本1.0.1-rsc
 *
 * @param hspObj
 * @param allRemoteHspPath
 * @private
 */
export const compareIfSetRemoteHsp = (hspObj: RemoteHspOpt, allRemoteHspPath: Map<string, RemoteHspOpt>): boolean => {
  if (!allRemoteHspPath.has(hspObj.hspFileName)) {
    return true;
  }
  const storedHspObj: RemoteHspOpt | undefined = allRemoteHspPath.get(hspObj.hspFileName);
  if (storedHspObj) {
    const maxHspVersion = semverMaxSatisfying([hspObj.hspVersion, storedHspObj.hspVersion]);
    return maxHspVersion === hspObj.hspVersion;
  }
  return true;
};

/**
 * ver1大于ver2返回1 小于返回-1 相等返回0 现版本比较方法为 正式版本1.0.1 > 正式版本1.0.0 正式版本1.0.1 > 先行版本1.0.1-rs
 *  正式版本1.0.1 > 先行版本1.0.2-rsc  先行版本1.0.1-rsc  > 先行版本1.0.1-rs
 *
 * @param versions
 */
export function semverMaxSatisfying(versions: string[]) {
  const maxSatisfyingVersion = maxSatisfying(versions, '*');
  return maxSatisfyingVersion || maxSatisfying(versions, '*', { includePrerelease: true, loose: true });
}

/**
 * 获取签名后的remoteHsp的数据信息
 *
 * @param service
 * @param productName
 */
export function getSignRemoteHspMetadata(service: ModuleTaskService, productName: string): RemoteHspMetadata[] | undefined {
  const projectModel = service.getProjectModel();
  const remoteHspArr: RemoteHspMetadata[] = [];
  if (!isSigned(projectModel)) {
    return undefined;
  }
  const signedRemoteHspInfo = service.getOhpmRemoteHspAllInfo(service, productName, true);
  Object.entries(signedRemoteHspInfo).forEach(([key, value]) => {
    const remoteHspObj: RemoteHspMetadata = {
      hspName: value.signedRemoteHspPath ? path.basename(value.signedRemoteHspPath) : '',
      hspVersion: value.version,
      hspPath: value.signedRemoteHspPath ?? '',
      soPath: value.soPath ?? '',
    };
    remoteHspArr.push(remoteHspObj);
  });
  return remoteHspArr;
}

/**
 * 获取hsp的packageName和remoteHsp路径的映射关系
 *
 * @param service
 * @param npmDependencies
 */
export function getRemoteHspPathMap(service: ModuleTaskService | ProjectTaskService, npmDependencies: Dependency[]): Map<string, string> {
  const projectModel = service.getProjectModel();
  const remoteHspPathMap: Map<string, string> = new Map<string, string>();
  const allRemoteHspInfoMap: Map<string, RemoteHspOpt> = new Map<string, RemoteHspOpt>();
  const projectOhpmPath = projectModel.getRemoteHspPath();
  if (service instanceof ModuleTaskService) {
    const moduleModule = service.getModuleModel();
    const moduleOhpmPath = moduleModule.getRemoteHspPath();
    initSignRemoteHspMap(moduleOhpmPath, allRemoteHspInfoMap, npmDependencies);
  }
  initSignRemoteHspMap(projectOhpmPath, allRemoteHspInfoMap, npmDependencies);
  allRemoteHspInfoMap.forEach((item) => {
    const hspFileName = item.hspFileName;
    remoteHspPathMap.set(item.hspName, hspFileName);
  });
  return remoteHspPathMap;
}

/**
 * 初始化在.hsp目录下的remote hsp的相关信息
 *
 * @param remoteHspPath
 * @param allRemoteHspPathMap
 * @param npmDependencies
 */
export function initSignRemoteHspMap(remoteHspPath: string, allRemoteHspPathMap: Map<string, RemoteHspOpt>, npmDependencies: Dependency[]) {
  if (!fse.existsSync(remoteHspPath)) {
    return;
  }
  const hspModules = fse.readdirSync(remoteHspPath);
  for (const hspDirItem of hspModules) {
    const hspDirPath = path.resolve(remoteHspPath, hspDirItem);
    const currentRemoteHspObj: RemoteHspOpt | undefined = getRemoteHspObj(hspDirPath, hspDirItem, _log);
    if (currentRemoteHspObj && compareIfSetRemoteHsp(currentRemoteHspObj, allRemoteHspPathMap)) {
      npmDependencies.forEach( dependencies => {
        if(dependencies.getPackageName() === currentRemoteHspObj.hspName) {
          allRemoteHspPathMap.set(currentRemoteHspObj.hspFileName, { ...currentRemoteHspObj });
        }
      });
    }
  }
}
